﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using SBS.Common;
using System.Web;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Linq;
using System.IO;

namespace SBS.Common
{
   /// <summary>
   /// C# XML 基础类库扩展
   /// </summary>
    
   public static class XmlExtension
        {
            /// <summary>
            /// 遍历 XmlNodeList 集合，每个元素都传入委托 F。
            /// </summary>
            /// <param name="NodeList"></param>
            /// <param name="F"></param>
           public static void Each(this XmlNodeList NodeList, Action<XmlNode> F)
           {
               NodeList.Select(n => n).ForEach(F);               
           }
            /// <summary>
            /// 遍历 XmlNodeList 集合，每个元素都传入委托 F，委托返回泛型值。Each 函数返回所有泛型值的数组。
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="NodeList"></param>
            /// <param name="F"></param>
           /// <returns>函数返回所有委托返回的值数组。</returns>
           public static T[] Each<T>(this XmlNodeList NodeList, Func<XmlNode, T> F)
           {
               T[] TList = new T[NodeList.Count];
               int Counter = 0;               
               foreach (XmlNode Item in NodeList)
               {
                   TList[Counter++] = F(Item);
               }
               return TList;
           }
           
            public static List<T> Select<T>(this XmlNodeList NodeList, Func<XmlNode, T> F)
            {
                List<T> Arr = new List<T>();
                foreach(XmlNode Node in NodeList)
                {
                    Arr.Add(F(Node));
                }
                return Arr;
            }
            public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this XmlNodeList NodeList, Func<XmlNode, TKey> Key, Func<XmlNode, TValue> Value)
            {
                List<XmlNode> Arr = NodeList.Select(n=>n);
                return Arr.ToDictionary(Key, Value);
                
                //foreach (XmlNode Node in NodeList)
                //{
                //    Arr.Add(F(Node));
                //}
                //return Arr;
            }
            public static List<XmlNode> OrderBy(this XmlNodeList NodeList, Func<XmlNode, XmlNode, int> Comparison)
            {
                List<XmlNode> Temp = NodeList.Select(n => n);
                Comparison<XmlNode> cc = new Comparison<XmlNode>(Comparison);
                Temp.Sort(cc);
                return Temp;
            }

            /// <summary>
            /// NodeList 的中每个元素都执行 XPath 查询，XPath 表达式的轴必须从单个 Node 开始计算。仅可查询 Node 的属性与 InnerText。
            /// </summary>
            /// <param name="NodeList"></param>
            /// <param name="XPath"></param>
            /// <returns></returns>
            public static List<XmlNode> OrderBy(this XmlNodeList NodeList, string XPath)
            {
                return NodeList.OrderBy((m, n) => 
                {
                    XmlNode x = m.SelectSingleNode(XPath);
                    XmlNode y = n.SelectSingleNode(XPath);
                    if(x.NodeType == XmlNodeType.Element)
                    {
                        return string.Compare(x.InnerText, y.InnerText);
                    }else
                    {
                        return string.Compare(x.Value, y.Value);
                    }
                });                 
            }

            public static int RemoveAll(this XmlNodeList NodeList)
            {
                int Counter = 0;
                foreach (XmlNode Node in NodeList)
                {
                    Node.ParentNode.RemoveChild(Node);
                    Counter++;
                }
                return Counter;
            }

            public static XmlNodeList SelectNodes(this XmlNode Node, string XPath, params string[] Args)
            {
                return Node.SelectNodes(string.Format(XPath, Args));
            }
            public static XmlNodeList SelectNodes(this XmlNode Node, XmlNamespaceManager nsmgr, string XPath, params string[] Args)
            {
                return Node.SelectNodes(string.Format(XPath, Args), nsmgr);
            }
            public static XmlNode SelectSingleNode(this XmlNode Node, string XPath, params string[] Args)
            {
                return Node.SelectSingleNode(string.Format(XPath, Args));
            }
            public static XmlNode SelectSingleNode(this XmlNode Node, XmlNamespaceManager nsmgr, string XPath, params string[] Args)
            {
                return Node.SelectSingleNode(string.Format(XPath, Args), nsmgr);
            }

            public static bool SetAttribute(this XmlNode Node, string Name, string Value)
            {
                if (Node.NodeType != XmlNodeType.Element) return false;
                if (Node.Attributes[Name] == null)
                {
                    XmlAttribute Attr = Node.OwnerDocument.CreateAttribute(Name);
                    Attr.Value = Value;
                    Node.Attributes.Append(Attr);
                }
                else
                {
                    Node.Attributes[Name].Value = Value;
                }
                return true;
            }

            public static string GetAttribute(this XmlNode Node, string Name)
            {
                if (Node.NodeType != XmlNodeType.Element) return null;
                XmlElement Elem = (XmlElement)Node;
                if (Elem.HasAttribute(Name) == false)
                {
                    return null;
                }
                return Elem.GetAttribute(Name);
            }

            public static bool HasAttribute(this XmlNode Node, string Name)
            {
                if (Node.NodeType != XmlNodeType.Element) return false;
                XmlElement Elem = (XmlElement)Node;
                return Elem.HasAttribute(Name);
            }
            /// <summary>
            /// 加载文件，默认采用 FileShare.ReadWrite 共享方式。在加载过程中，允许其他进程对目标文件进行 ReadWrite 操作。
            /// </summary>
            /// <param name="Dom">XmlDocument 对象</param>
            /// <param name="FileFullPath">目标文件路径</param>
            public static void LoadFile(this XmlDocument Dom, string FileFullPath)
            {
                LoadFile(Dom, FileFullPath, FileShare.ReadWrite);
            }
            /// <summary>
            /// 加载文件，默认采用 FileShare.ReadWrite 共享方式。在加载过程中，允许其他进程对目标文件进行 ReadWrite 操作。
            /// </summary>
            /// <param name="Dom">XmlDocument 对象</param>
            /// <param name="FileFullPath">目标文件路径</param>
            /// <param name="FileShare">文件共享方式。默认为 FileShare.ReadWrite</param>
            public static void LoadFile(this XmlDocument Dom, string FileFullPath, FileShare FileShare)
            {
                using (FileStream fs = new FileStream(FileFullPath, FileMode.Open, FileAccess.Read, FileShare))
                {
                    Dom.Load(fs);
                }                
            }
           /// <summary>
            /// 保存XmlDocument对象到文件，默认启用 FileShare.Read，保存过程中，其他进程仅可使用 Read 操作访问 FileFullPath 位置的文件。
           /// </summary>
           /// <param name="Dom">XmlDocument 对象</param>
           /// <param name="FileFullPath">文件存储的路径</param>
            public static void SaveToFile(this XmlDocument Dom, string FileFullPath)
            {
                SaveToFile(Dom, FileFullPath, FileShare.Read);
            }
            /// <summary>
            /// 保存XmlDocument对象到文件，默认启用 FileShare.Read，写入文件的过程中，其他进程仅可使用 Read 操作访问 FileFullPath 位置的文件。
            /// </summary>
            /// <param name="Dom">XmlDocument 对象</param>
            /// <param name="FileFullPath">文件存储的路径</param>
            /// <param name="FileShare">文件共享方式。默认为 FileShare.Read</param>
            public static void SaveToFile(this XmlDocument Dom, string FileFullPath, FileShare FileShare)
            {
                
                using (FileStream fs = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write, FileShare))
                {
                    Dom.Save(fs);
                }                
            }

            public static XElement ToXElement(this XmlNode Node, LoadOptions Options)
            {
                using (XmlNodeReader reader = new XmlNodeReader(Node))
                {
                    return XElement.Load(reader, Options);
                }
            }

            public static XElement ToXElement(this XmlNode Node)
            {
                using (XmlNodeReader reader = new XmlNodeReader(Node))
                {
                    return XElement.Load(reader);
                }
            }

            public static XDocument ToXDocument(this XmlDocument Document, LoadOptions Options)
            {
                using (XmlNodeReader reader = new XmlNodeReader(Document))
                {
                    return XDocument.Load(reader, Options);
                }
            }

            public static XDocument ToXDocument(this XmlDocument Document)
            {
                return Document.ToXDocument();
            }
        }

   
    
}
